/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package polandballgame;
import java.awt.Graphics;

// i/o
import java.io.*;
import java.util.Scanner;
import java.util.Random;

/**
 *
 * @author POed
 */
public class Engine {
    
    public enum Direction {
        
        DirectionUp,
        DirectionRight,
        DirectionDown,
        DirectionLeft
    }
    
    static public int cellSize = 40;
    static public int width = 30;
    static public int height = 17;
    
    // data:
    Countryball hero;
    private GameObject field[][];
    GameView gameView;
    StatusBar statusBar;
    
    // methods:
    public Engine() {
        
        this.loadData();
    }
    
    public void setView(GameView view) {
        
        gameView = view;
        gameView.setEngine(this);
        gameView.repaint();
    }
    
    public void setStatusBar(StatusBar view) {
        
        statusBar = view;
        statusBar.setEngine(this);
        if (hero != null) {
            statusBar.setHeroStats(hero);
        }
    }
    
    public void loadData(String map) {
        
        // read text from file:
        StringBuilder text = new StringBuilder();
        String nl = System.getProperty("line.separator");
        try {
            Scanner scanner = new Scanner(new FileInputStream(map));
            try {
                while (scanner.hasNextLine()) {
                    text.append(scanner.nextLine()).append(nl);
                }
            }
            finally {
                scanner.close();
            }
        }
        catch (IOException e) {
            System.out.println("Unable to create "+map+": "+e.getMessage());
        }
        
        // parsing text and fill field with data:
        if (text.length() > 0) {
            
            field = new GameObject[Engine.height][Engine.width];
            String lines[] = text.toString().split(nl);
            
            if (lines.length != Engine.height) {
                System.out.println("Corrupted file");
                return;
            }
            
            for (int i = 0; i < Engine.height; ++i) {
                
                String line[] = lines[i].split(" ");
                
                if (line.length != Engine.width) {
                    System.out.println("Corrupted file");
                    return;
                }
                
                for (int j = 0; j < Engine.width; ++j) {
                    
                    switch (Integer.parseInt(line[j])) {
                        
                        case 0:
                            break;
                            
                        case 1:
                            field[i][j] = new WallSegment(j, i);
                            break;
                            
                        case 2:
                            field[i][j] = new MineralSegment(j, i);
                            break;
                        case 4:
                            field[i][j] = new SwampObject(j, i);
                            break;
                            
                        case 7:
                            hero = new Polandball(j, i);
                            field[i][j] = hero;
                            break;
                            
                        case 8:
                            hero = new Countryball(j, i);
                            field[i][j] = hero;
                            break;
                            
                        default:
                            System.out.println("Corrupted file");
                            return;
                    }
                }
            }
            if (gameView != null) {
                gameView.repaint();
            }
            if (statusBar != null) {
                statusBar.setHeroStats(hero);
            }
        }
    }
    
    private void loadData() {
        
        this.loadData("./maps/map_0.pbm");
    }
    
    public void draw(Graphics context) {
        
        // observer must exist!
        if (hero != null) {
            
            hero.draw(context);
        
            for (int i = 0; i < Engine.height; ++i) {
                for (int j = 0; j < Engine.width; ++j) {

                    if (field[i][j] != null && field[i][j] != hero) {
                        
                        if (hero.type == 7) {
                            // this blind plumber again:
                            Polandball poland = (Polandball)hero;
                            // calculating field of view:
                            if (poland.isObjectVisible(field[i][j])) {
                                // hero is close enough to show him object
                                field[i][j].draw(context);
                            }
                        }
                        else {
                            // 
                            field[i][j].draw(context);
                        }
                    }
                }
            }
        }
    }
    
    private boolean moveObject(GameObject object, Direction direction) {
        
        int x = object.x;
        int y = object.y;
        
        switch (direction) {
            
            case DirectionUp:
                --y;
                break;
            case DirectionRight:
                ++x;
                break;
            case DirectionDown:
                ++y;
                break;
            case DirectionLeft:
                --x;
                break;
            default:
                break;
        }
        // check new position:
        if (x < 0 || x >= Engine.width || y < 0 || y >= Engine.height) {
            return false;
        }
        
        boolean canMove = true;
        GameObject background = null;
        GameObject item = null;
        
        if (object == hero) {
			
            if (hero.background != null) {

                if (hero.background.type == 4 && !((SwampObject)hero.background).tryToLeave()) {
                    //canMove = false;
                    return false;
                }
            }
        }
        
        // check for existing objects:
        if (field[y][x] != null) {
            
            if (object == hero) {
                // sometimes hero can move trough objects and even collect them
                if (field[y][x].passable) {
                    // can move and grab item
                    item = field[y][x];
                    canMove = true;
                }
                else {
                    // calculate hero power
                    Random random = new Random();
                    int power = hero.type == 7 ? ((Polandball)hero).minerals * 2 : 0;
                    if (random.nextInt(100) < power) {
                        // porter move:
                        this.moveObject(field[y][x], direction);
                        
                        if (field[y][x] == null) {
                            // object was successfully moved, hero takes his place
                            canMove = true;
                        }
                        else {
                            // object still in place
                            canMove = false;
                        }
                    }
                    else {
                        // not this time
                        canMove = false;
                    }
                }
            }
            else {
                canMove = false;
            }
        }
        else {
            // no objects behind
            canMove = true;
        }
        
        if (canMove) {
            
            if (object == hero) {
                background = hero.background;
                hero.background = null;
                
                hero.grabItem(item);
            }
            
            // can move now
            field[y][x] = object;
            field[object.y][object.x] = background;
            // set new x, y
            object.x = x;
            object.y = y;
        }
        
        // repaint changes:
        if (gameView != null) {
            gameView.repaint();
        }
        if (statusBar != null) {
            statusBar.setHeroStats(hero);
        }
        
        return canMove;
    }
    
    public boolean moveHero(Direction direction) {
        
        return moveObject(hero, direction);
    }
}
